package com.fuego.creditsystemcommodity.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fuego.creditsystemcommodity.mapper.RoomOrderMapper;
import com.fuego.creditsystemcommodity.service.IRoomInfoService;
import com.fuego.creditsystemcommodity.service.IRoomOrderService;
import com.fuego.creditsystemcommodity.service.IRoomService;
import jakarta.annotation.Resource;
import org.example.dto.Result;
import org.example.entity.RoomOrder;
import org.example.utils.RedisIdWorker;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static org.example.utils.RedisConstants.ROOM_INFO_STOCK_KEY;

@Service
public class RoomOrderServiceImpl extends ServiceImpl<RoomOrderMapper, RoomOrder> implements IRoomOrderService {

    @Resource
    private IRoomInfoService roomInfoService;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private RedisIdWorker redisIdWorker;
    @Resource
    private IRoomService roomService;

    @Override
    @Transactional
    public Result roomInfo(Long roomId, Long userId, LocalDateTime startDate, LocalDateTime endDate, Integer amount) {
        // 验证输入参数
        if (roomId == null || userId == null || startDate == null || endDate == null || amount == null || amount <= 0) {
            return Result.fail("参数不完整或无效");
        }



        // 生成月份列表
        List<LocalDate> days = new ArrayList<>();
        LocalDate current = startDate.toLocalDate();
        while (!current.isAfter(endDate.toLocalDate())) {
            days.add(current);
            current = current.plusDays(1);
        }

        if (days.size() != amount) {
            return Result.fail("入住天数与amount参数不匹配，预期 " + days.size() + " 日，收到 " + amount);
        }

        // 检查并聚合 Redis 库存
        Map<LocalDate, Long> stockMap = new HashMap<>();
        List<String> stockKeys = new ArrayList<>();
        for (LocalDate day : days) {
            String stockKey = ROOM_INFO_STOCK_KEY + roomId + ":" + startDate;
            String stockStr = stringRedisTemplate.opsForValue().get(stockKey);
            if (stockStr == null) {
                return Result.fail("库存键不存在: " + stockKey);
            }
            long stock = Long.parseLong(stockStr);
            if (stock <= 0) {
                return Result.fail("库存不足: " + day.format(DateTimeFormatter.ISO_LOCAL_DATE));
            }
            stockMap.put(day, stock);
            stockKeys.add(stockKey);
        }

        // 扣减 Redis 库存
        try {
            for (String stockKey : stockKeys) {
                Long newStock = stringRedisTemplate.opsForValue().increment(stockKey, -1);
                if (newStock == null || newStock < 0) {
                    throw new RuntimeException("Redis 库存扣减失败: " + stockKey);
                }
            }
        } catch (Exception e) {
            log.error("Redis 库存扣减失败", e);
            // 回滚已扣减的 Redis 库存
            for (String stockKey : stockKeys) {
                stringRedisTemplate.opsForValue().increment(stockKey, 1);
            }
            return Result.fail("Redis 库存扣减失败: " + e.getMessage());
        }

        // 创建订单并扣减数据库库存
        List<Long> orderIds = new ArrayList<>();
        try {
            for (LocalDate day : days) {
                long orderId = redisIdWorker.nextId("roomorder");
                if (orderId == 0) {
                    throw new RuntimeException("生成订单ID失败");
                }

                RoomOrder roomOrder = new RoomOrder();
                roomOrder.setRoomId(roomId);
                roomOrder.setUserId(userId);
                roomOrder.setId(orderId);
                roomOrder.setStatus(1); // 订单状态：未支付
                roomOrder.setPayType(1); // 默认支付方式：信用额度支付
                roomOrder.setCreateTime(LocalDateTime.now());
                roomOrder.setCheckinDate(startDate.toLocalDate()); // 设置入住日期
                roomOrder.setCheckoutDate(endDate.toLocalDate()); // 设置入住日期
                roomOrder.setCurrentPrice(roomService.getById(roomId).getCurrentPrice()/100);
                roomOrder.setAmount(amount);
                roomOrder.setTotal(roomService.getById(roomId).getCurrentPrice()*amount/100);

                createRoomOrder(roomOrder, day);
                orderIds.add(orderId);
            }

            return Result.ok(orderIds);
        } catch (Exception e) {
            log.error("订单创建或数据库库存扣减失败", e);
            // 回滚 Redis 库存
            for (String stockKey : stockKeys) {
                stringRedisTemplate.opsForValue().increment(stockKey, 1);
            }
            // 事务会自动回滚数据库操作
            return Result.fail("订单创建失败: " + e.getMessage());
        }
    }

    @Transactional
    public void createRoomOrder(RoomOrder roomOrder, LocalDate checkinDate) {
        // 扣减数据库库存
        boolean success = roomInfoService.update()
                .setSql("stock = stock - 1")
                .eq("room_id", roomOrder.getRoomId())
                .eq("checkin_date", checkinDate)
                .gt("stock", 0)
                .update();
        if (!success) {
            log.error("数据库库存不足: room_id=" + roomOrder.getRoomId() + ", checkin_date=" + checkinDate);
            throw new RuntimeException("数据库库存不足: " + checkinDate);
        }

        // 保存订单
        save(roomOrder);
    }

    @Override
    public Result queryAllOrders(Long userId) {
        if (userId == null) {
            return Result.fail("用户ID不能为空");
        }
        List<RoomOrder> roomOrders = getBaseMapper().queryAllOrders(userId);
        return Result.ok(roomOrders);
    }

    @Override
    @Transactional
    public Result refund(Long orderId) {
        if (orderId == null) {
            return Result.fail("订单ID不能为空");
        }
        RoomOrder order = this.query()
                .eq("id", orderId)
                .list()
                .stream()
                .findFirst()
                .orElse(null);

        if (order == null) {
            return Result.fail("订单不存在");
        }
        if (order.getStatus() == 2) {
            return Result.fail("订单已退款");
        }
        
        // 恢复数据库库存
        boolean success;

        for (int i = 0; i < order.getAmount(); i++) {
            // 恢复 Redis 库存
            LocalDate refundDate = order.getCheckinDate().plusDays(i);
            String stockKey = "roominfo:stock:" +refundDate+ order.getRoomId() + ":" + order.getCheckinDate().format(DateTimeFormatter.ISO_LOCAL_DATE);
            stringRedisTemplate.opsForValue().increment(stockKey, 1);

            // 恢复数据库库存
            success = roomInfoService.update()
                    .setSql("stock = stock + 1")
                    .eq("room_id", order.getRoomId())
                    .eq("checkin_date", refundDate)
                    .update();
            if (!success) {
                log.error("数据库库存恢复失败: room_id=" + order.getRoomId() + ", checkin_date=" + order.getCheckinDate());
                throw new RuntimeException("数据库库存恢复失败: " + order.getCheckinDate());
            }
        }

        // 更新订单状态
        success = this.update()
                .eq("id", orderId)
                .set("status", 2) // 设置为已退款
                .set("refund_time", LocalDateTime.now())
                .update();
        if (!success) {
            return Result.fail("退款失败");
        }

        return Result.ok("退款成功");
    }
}
